package com.thz.system.utils.svg;

import com.thz.common.enums.ErrorCode;
import com.thz.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
import java.util.List;

/**
 * 图像转SVG工具类（优化版）
 * 使用快速像素块方法生成SVG，适合追求速度的场景
 * 
 * @author THZ
 * @date 2025
 */
@Slf4j
public class ImageToSvgUtilsOptimized {
    
    private static final int MAX_DIMENSION = 1200;
    
    /**
     * 将图像文件转换为彩色矢量SVG
     * 
     * @param inputPath 输入图像路径
     * @param outputPath 输出SVG路径
     * @param width 目标宽度（null则保持原始尺寸）
     * @param height 目标高度（null则保持原始尺寸）
     * @param keepAspectRatio 是否保持宽高比
     * @param colorCount 颜色数量（用于量化，建议8-32）
     * @param precision 矢量化精度（1-10，值越高越精细）
     */
    public static void convertImageToSvg(String inputPath, String outputPath, 
                                         Integer width, Integer height, 
                                         Boolean keepAspectRatio,
                                         Integer colorCount, Integer precision) {
        long startTime = System.currentTimeMillis();
        try {
            File inputFile = new File(inputPath);
            if (!inputFile.exists()) {
                throw new BusinessException(ErrorCode.FILE_NOT_FOUND);
            }
            
            log.info("开始优化版彩色矢量化转换: {}", inputPath);
            
            // 设置默认值
            if (colorCount == null || colorCount <= 0) {
                colorCount = 16;
            }
            if (precision == null || precision < 1 || precision > 10) {
                precision = 5;
            }
            
            // 读取和预处理图像
            BufferedImage image = ImageIO.read(inputFile);
            if (image == null) {
                throw new BusinessException(ErrorCode.FILE_TYPE_INVALID, "无法读取图像文件");
            }
            
            // 智能缩放
            image = smartResize(image, width, height, keepAspectRatio);
            
            // 快速颜色量化
            image = quantizeColors(image, colorCount);
            
            // 生成SVG
            String svgContent = generateSvg(image, precision);
            
            // 写入文件
            try (BufferedWriter writer = new BufferedWriter(new FileWriter(outputPath))) {
                writer.write(svgContent);
            }
            
            long duration = System.currentTimeMillis() - startTime;
            log.info("优化版彩色矢量化转换成功: {} -> {}，耗时: {}ms", inputPath, outputPath, duration);
            
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("优化版彩色矢量化转换失败", e);
            throw new BusinessException(ErrorCode.CONVERSION_FAILED, "图像转SVG失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 智能缩放：自动处理大图像
     */
    private static BufferedImage smartResize(BufferedImage original, Integer targetWidth, 
                                            Integer targetHeight, Boolean keepAspectRatio) {
        int origWidth = original.getWidth();
        int origHeight = original.getHeight();
        
        int newWidth = origWidth;
        int newHeight = origHeight;
        
        if (targetWidth != null || targetHeight != null) {
            if (targetWidth != null && targetHeight != null) {
                if (keepAspectRatio == null || keepAspectRatio) {
                    double ratio = Math.min((double) targetWidth / origWidth, 
                                           (double) targetHeight / origHeight);
                    newWidth = (int) (origWidth * ratio);
                    newHeight = (int) (origHeight * ratio);
                } else {
                    newWidth = targetWidth;
                    newHeight = targetHeight;
                }
            } else if (targetWidth != null) {
                double ratio = (double) targetWidth / origWidth;
                newWidth = targetWidth;
                newHeight = (int) (origHeight * ratio);
            } else {
                double ratio = (double) targetHeight / origHeight;
                newWidth = (int) (origWidth * ratio);
                newHeight = targetHeight;
            }
        }
        
        // 自动限制最大尺寸
        if (newWidth > MAX_DIMENSION || newHeight > MAX_DIMENSION) {
            double ratio = Math.min((double) MAX_DIMENSION / newWidth, 
                                   (double) MAX_DIMENSION / newHeight);
            newWidth = (int) (newWidth * ratio);
            newHeight = (int) (newHeight * ratio);
            log.info("图像尺寸过大，自动缩放到: {}x{}", newWidth, newHeight);
        }
        
        if (newWidth == origWidth && newHeight == origHeight) {
            return original;
        }
        
        BufferedImage resized = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = resized.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.drawImage(original, 0, 0, newWidth, newHeight, null);
        g.dispose();
        
        return resized;
    }
    
    /**
     * 快速颜色量化
     */
    private static BufferedImage quantizeColors(BufferedImage image, int colorCount) {
        int width = image.getWidth();
        int height = image.getHeight();
        
        // 采样像素
        int sampleSize = Math.min(width * height, 5000);
        int[] samples = samplePixels(image, sampleSize);
        
        // 使用K-means聚类找到主要颜色
        int[] palette = kMeansClustering(samples, colorCount);
        
        // 映射所有像素到最近的调色板颜色
        BufferedImage quantized = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int rgb = image.getRGB(x, y);
                int nearestColor = findNearestColor(rgb, palette);
                quantized.setRGB(x, y, nearestColor);
            }
        }
        
        return quantized;
    }
    
    /**
     * 采样像素
     */
    private static int[] samplePixels(BufferedImage image, int sampleSize) {
        int width = image.getWidth();
        int height = image.getHeight();
        int totalPixels = width * height;
        
        if (totalPixels <= sampleSize) {
            int[] pixels = new int[totalPixels];
            int idx = 0;
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    pixels[idx++] = image.getRGB(x, y);
                }
            }
            return pixels;
        }
        
        // 均匀采样
        int[] samples = new int[sampleSize];
        Random random = new Random(42);
        
        for (int i = 0; i < sampleSize; i++) {
            int x = random.nextInt(width);
            int y = random.nextInt(height);
            samples[i] = image.getRGB(x, y);
        }
        
        return samples;
    }
    
    /**
     * K-means聚类算法
     */
    private static int[] kMeansClustering(int[] pixels, int k) {
        // 初始化聚类中心
        int[] centers = new int[k];
        Random random = new Random(42);
        Set<Integer> selectedIndices = new HashSet<>();
        
        for (int i = 0; i < k; i++) {
            int idx;
            do {
                idx = random.nextInt(pixels.length);
            } while (selectedIndices.contains(idx));
            selectedIndices.add(idx);
            centers[i] = pixels[idx];
        }
        
        // 迭代优化（最多10次）
        for (int iter = 0; iter < 10; iter++) {
            int[] assignments = new int[pixels.length];
            for (int i = 0; i < pixels.length; i++) {
                assignments[i] = findNearestColorIndex(pixels[i], centers);
            }
            
            // 更新聚类中心
            int[] newCenters = new int[k];
            for (int c = 0; c < k; c++) {
                long sumA = 0, sumR = 0, sumG = 0, sumB = 0;
                int count = 0;
                
                for (int i = 0; i < pixels.length; i++) {
                    if (assignments[i] == c) {
                        int rgb = pixels[i];
                        sumA += (rgb >> 24) & 0xFF;
                        sumR += (rgb >> 16) & 0xFF;
                        sumG += (rgb >> 8) & 0xFF;
                        sumB += rgb & 0xFF;
                        count++;
                    }
                }
                
                if (count > 0) {
                    int a = (int) (sumA / count);
                    int r = (int) (sumR / count);
                    int g = (int) (sumG / count);
                    int b = (int) (sumB / count);
                    newCenters[c] = (a << 24) | (r << 16) | (g << 8) | b;
                } else {
                    newCenters[c] = centers[c];
                }
            }
            
            // 检查收敛
            boolean converged = true;
            for (int c = 0; c < k; c++) {
                if (centers[c] != newCenters[c]) {
                    converged = false;
                    break;
                }
            }
            
            centers = newCenters;
            if (converged) {
                break;
            }
        }
        
        return centers;
    }
    
    /**
     * 找到最近的颜色
     */
    private static int findNearestColor(int rgb, int[] palette) {
        int nearestIdx = findNearestColorIndex(rgb, palette);
        return palette[nearestIdx];
    }
    
    /**
     * 找到最近的颜色（返回索引）
     */
    private static int findNearestColorIndex(int rgb, int[] palette) {
        int minDistance = Integer.MAX_VALUE;
        int nearestIdx = 0;
        
        int a = (rgb >> 24) & 0xFF;
        int r = (rgb >> 16) & 0xFF;
        int g = (rgb >> 8) & 0xFF;
        int b = rgb & 0xFF;
        
        for (int i = 0; i < palette.length; i++) {
            int pa = (palette[i] >> 24) & 0xFF;
            int pr = (palette[i] >> 16) & 0xFF;
            int pg = (palette[i] >> 8) & 0xFF;
            int pb = palette[i] & 0xFF;
            
            int distance = (a - pa) * (a - pa) + 
                          (r - pr) * (r - pr) + 
                          (g - pg) * (g - pg) + 
                          (b - pb) * (b - pb);
            
            if (distance < minDistance) {
                minDistance = distance;
                nearestIdx = i;
            }
        }
        
        return nearestIdx;
    }
    
    /**
     * 生成SVG（使用像素块方法）
     */
    private static String generateSvg(BufferedImage image, Integer precision) {
        int width = image.getWidth();
        int height = image.getHeight();
        
        // 计算块大小
        int blockSize = Math.max(1, 11 - precision);
        
        StringBuilder svg = new StringBuilder();
        svg.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
        svg.append("<!-- Generated by Optimized Vectorization -->\n");
        svg.append("<svg xmlns=\"http://www.w3.org/2000/svg\" ");
        svg.append("width=\"").append(width).append("\" ");
        svg.append("height=\"").append(height).append("\" ");
        svg.append("viewBox=\"0 0 ").append(width).append(" ").append(height).append("\">\n");
        
        // 提取颜色区域
        Map<Integer, List<Rectangle>> colorRegions = new HashMap<>();
        
        for (int y = 0; y < height; y += blockSize) {
            for (int x = 0; x < width; x += blockSize) {
                int blockWidth = Math.min(blockSize, width - x);
                int blockHeight = Math.min(blockSize, height - y);
                
                // 使用中心点颜色
                int centerX = x + blockWidth / 2;
                int centerY = y + blockHeight / 2;
                int rgb = image.getRGB(centerX, centerY);
                
                Rectangle rect = new Rectangle(x, y, blockWidth, blockHeight);
                colorRegions.computeIfAbsent(rgb, k -> new ArrayList<>()).add(rect);
            }
        }
        
        // 为每个颜色生成矩形
        for (Map.Entry<Integer, List<Rectangle>> entry : colorRegions.entrySet()) {
            int rgb = entry.getKey();
            Color color = new Color(rgb, true);
            
            if (color.getAlpha() < 10) {
                continue;
            }
            
            // 合并相邻矩形
            List<Rectangle> optimizedRects = mergeRectangles(entry.getValue());
            
            for (Rectangle rect : optimizedRects) {
                svg.append("  <rect x=\"").append(rect.x).append("\" y=\"").append(rect.y).append("\" ");
                svg.append("width=\"").append(rect.width).append("\" ");
                svg.append("height=\"").append(rect.height).append("\" ");
                svg.append("fill=\"").append(colorToHex(color)).append("\"");
                if (color.getAlpha() < 255) {
                    svg.append(" opacity=\"").append(String.format("%.2f", color.getAlpha() / 255.0)).append("\"");
                }
                svg.append("/>\n");
            }
        }
        
        svg.append("</svg>");
        
        return svg.toString();
    }
    
    /**
     * 合并相邻的矩形
     */
    private static List<Rectangle> mergeRectangles(List<Rectangle> rectangles) {
        if (rectangles.size() <= 1) {
            return rectangles;
        }
        
        List<Rectangle> merged = new ArrayList<>();
        rectangles.sort(Comparator.comparingInt((Rectangle r) -> r.y).thenComparingInt(r -> r.x));
        
        Rectangle current = null;
        for (Rectangle rect : rectangles) {
            if (current == null) {
                current = new Rectangle(rect);
            } else if (current.y == rect.y && current.height == rect.height && 
                      current.x + current.width == rect.x) {
                // 水平合并
                current.width += rect.width;
            } else {
                merged.add(current);
                current = new Rectangle(rect);
            }
        }
        
        if (current != null) {
            merged.add(current);
        }
        
        return merged;
    }
    
    /**
     * 将颜色转换为十六进制字符串
     */
    private static String colorToHex(Color color) {
        return String.format("#%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue());
    }
    
    /**
     * 获取SVG文件的尺寸
     */
    public static int[] getSvgDimensions(String svgPath) {
        try {
            File svgFile = new File(svgPath);
            if (!svgFile.exists()) {
                log.error("SVG文件不存在: {}", svgPath);
                return new int[]{0, 0};
            }
            
            // 只读取前1000字节
            StringBuilder header = new StringBuilder();
            try (BufferedReader reader = new BufferedReader(new FileReader(svgFile))) {
                char[] buffer = new char[1000];
                int read = reader.read(buffer);
                if (read > 0) {
                    header.append(buffer, 0, read);
                }
            }
            
            String content = header.toString();
            
            int width = 0;
            int height = 0;
            
            java.util.regex.Pattern widthPattern = java.util.regex.Pattern.compile("width=[\"'](\\d+)[\"']");
            java.util.regex.Matcher widthMatcher = widthPattern.matcher(content);
            if (widthMatcher.find()) {
                width = Integer.parseInt(widthMatcher.group(1));
            }
            
            java.util.regex.Pattern heightPattern = java.util.regex.Pattern.compile("height=[\"'](\\d+)[\"']");
            java.util.regex.Matcher heightMatcher = heightPattern.matcher(content);
            if (heightMatcher.find()) {
                height = Integer.parseInt(heightMatcher.group(1));
            }
            
            if (width == 0 || height == 0) {
                java.util.regex.Pattern viewBoxPattern = java.util.regex.Pattern.compile(
                    "viewBox=[\"']\\s*[\\d.]+\\s+[\\d.]+\\s+([\\d.]+)\\s+([\\d.]+)[\"']");
                java.util.regex.Matcher viewBoxMatcher = viewBoxPattern.matcher(content);
                if (viewBoxMatcher.find()) {
                    width = (int) Double.parseDouble(viewBoxMatcher.group(1));
                    height = (int) Double.parseDouble(viewBoxMatcher.group(2));
                }
            }
            
            log.info("从SVG文件解析尺寸: {}x{}", width, height);
            return new int[]{width, height};
            
        } catch (Exception e) {
            log.error("获取SVG尺寸失败: {}", svgPath, e);
            return new int[]{0, 0};
        }
    }
}
